package fudan.se.project.config;

import fudan.se.project.domain.conference.Conference;
import fudan.se.project.repository.entity.conference.ConferenceRepository;
import fudan.se.project.util.date.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.Date;

import static fudan.se.project.domain.conference.Conference.ConferenceStage.*;

@EnableScheduling
@Configuration
@Slf4j
public class ConferenceScheduleConfig {

    private boolean isRunning = false;
    private Date currDate = null;

    private final ConferenceRepository conferenceRepository;

    private DateUtils dateUtils;

    @Autowired
    public ConferenceScheduleConfig(ConferenceRepository conferenceRepository, DateUtils dateUtils) {
        this.conferenceRepository = conferenceRepository;
        this.dateUtils = dateUtils;
    }

    private void run() {
        log.info("conference stage scheduled update started.");
        this.isRunning = true;
        currDate = new Date();
    }

    private void stop() {
        log.info("conference stage scheduled update stopped.");
        this.isRunning = false;
        currDate = null;
    }


    @Scheduled(cron = "0 1 0 * * ?")
    public void updateConferenceStage() {
        run();

        Iterable<Conference> conferences = conferenceRepository.findAll();
        for (Conference conference : conferences) {

            switch (conference.getStage()) {
                case CONTRIBUTION_START:
                    tryEndContribution(conference);
                    break;
                case FINAL_RELEASE:
                    tryStartConference(conference);
                    break;
                case CONFERENCE_START:
                    tryEndConference(conference);
                    break;
                case PREPARING:
                case CONTRIBUTION_END:
                case REVIEW_START:
                case REVIEW_END:
                case RESULT_RELEASE:
                case CONFERENCE_END:
                default:
                    doNothing();
            }
        }
        conferenceRepository.saveAll(conferences);


        stop();
    }

    private void doNothing() {
        //do nothing
    }

    private void tryEndContribution(Conference conference) {
        Date deadline = conference.getDeadline();
        if (conference.getStage().equals(CONTRIBUTION_START)
                && dateUtils.isRightOutOfRightBorderByOneDay(deadline, currDate)) {
            conference.setStage(CONTRIBUTION_END);
        }
    }

    private void tryStartConference(Conference conference) {
        Date dateStart = conference.getDateStart();
        if (conference.getStage().equals(FINAL_RELEASE)
                && currDate.after(dateStart)) {
            conference.setStage(CONFERENCE_START);
        }
    }

    private void tryEndConference(Conference conference) {
        Date dateEnd = conference.getDateEnd();
        if (conference.getStage().equals(CONTRIBUTION_START)
                && dateUtils.isRightOutOfRightBorderByOneDay(dateEnd, currDate)) {
            conference.setStage(CONFERENCE_END);
        }
    }


    public boolean isRunning() {
        return isRunning;
    }

}
